package com.open.capacity.tenant.config;

import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * JWT token过滤器
 * @program: security-demo
 * @author: GuoGaoJu
 * @create: 2023-04-06
 **/
@Configuration
public class JwtTokenFilter extends OncePerRequestFilter {
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        String path = httpServletRequest.getRequestURI();
        String method = httpServletRequest.getMethod();
        // 对于登录直接放行
        if ("/login".equals(path) && "POST".equals(method)){
            filterChain.doFilter(httpServletRequest,httpServletResponse);
            return;
        }
        //获取token并验证
        String authorization = httpServletRequest.getHeader("Authorization");
        if (!StrUtil.hasBlank(authorization)){
            //如果redis缓存中存在token且未过期，再验证
            Boolean aBoolean = redisTemplate.hasKey("token:" + authorization);
            //-1是没有设置过期时间、-2是没有该值、否则即使过期时间
            Long expire = redisTemplate.opsForValue().getOperations().getExpire("token:" + authorization);
            if ((!aBoolean) || (expire<=0)){
                logger.info("token不存在或已过期！");
                return;
            }
            //登出
            if ("/doLogout".equals(path) && "POST".equals(method)){
                filterChain.doFilter(httpServletRequest,httpServletResponse);
                return;
            }
            String jwt = authorization.replace("bearer ", "");
            //创建一个token解析器（test最为jwt生成token的签名是自定义的，一般作为配置固定值）
            JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("test")).build();
            DecodedJWT decodedJWT;
            try{
                decodedJWT = jwtVerifier.verify(jwt);
            } catch (Exception e){
                httpServletResponse.getWriter().write("token验证失败！！！");
                return;
            }
            //获取用户名、密码、角色权限
            String username = decodedJWT.getClaim("username").asString();
            String password = decodedJWT.getClaim("password").asString();
            List<String> roles = decodedJWT.getClaim("role").asList(String.class);
            ArrayList<SimpleGrantedAuthority> roleList = new ArrayList<>();
            roles.forEach(role -> {
                roleList.add(new SimpleGrantedAuthority(role));
            });
            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(username, password, roleList);
            SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            filterChain.doFilter(httpServletRequest,httpServletResponse);
            return;
        }
        httpServletResponse.getWriter().write("token验证失败！");
    }
}
